﻿/*
 * GdoSqlDataReader
 * 
 * initial implementation : 20.9.2008
 *
 * Copyright (c) Adam Sida, asida@centrum.cz.
 * All rights reserved.
 * 
 * for license see Petra.Gis.License.txt
 */
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using Petra.Gis.Geometry;
using Petra.Gis.DataServices;
using Petra.Gis.DataServices.GDO;
using Petra.Gis.DataServices.Metadata;


namespace Petra.Gis.DataServices.GDO.Sqlserver
{

  public class GdoSqlDataReader :  SpatialDbDataReader
  {

    private SqlDataReader _sqlDr;
    private FeatureMetadata _metadata;
    private GeometryFactory _gdoF;
    private List<string> _gfieldNames;



    internal GdoSqlDataReader(GdoSqlCommand command, SqlDataReader dr)
    {
      _sqlDr = dr;

      // load metadata here, data reader needs to know
      // which fields contain spatial data
      // for spatial field is value of varbinary or image translated
      // into geometry
      //try
      //{
      _metadata = command.Metadata; // Metadata;
        // load spatial fields into list
        _gfieldNames = new List<string>();
        foreach (SpatialFieldMetadata gfm in _metadata.GeometryFieldsMetadata)
          _gfieldNames.Add(gfm.Name);
      //}
      //catch { }

      //if (command.Extensions.ContainsKey("FeatureMetadata"))
      //  _metadata = (FeatureMetadata)command.Extensions["FeatureMetadata"];
      //else
      //  _metadata = null;

      //fill _gfieldNames

      //prepare geometry factory anyway
      _gdoF = new GeometryFactory();
    }
    




    public override int Depth
    {
      /*
       * Always return a value of zero if nesting is not supported.
       */
      get { return 0; }
    }






    public override bool IsClosed
    {
      /*
       * Keep track of the reader state - some methods should be
       * disallowed if the reader is closed.
       */
      get { return _sqlDr.IsClosed; }
    }





    public override int RecordsAffected
    {
      /*
       * RecordsAffected is only applicable to batch statements
       * that include inserts/updates/deletes. The sample always
       * returns -1.
       */
      get { return _sqlDr.RecordsAffected; }
    }





    public override void Close()
    {
      _sqlDr.Close();
    }





    public override bool NextResult()
    {
      return _sqlDr.NextResult();
    }





    public override bool Read()
    {
      return _sqlDr.Read();
    }





    public override DataTable GetSchemaTable()
    {
      return _sqlDr.GetSchemaTable();
    }






    public override int FieldCount
    {
      get { return _sqlDr.FieldCount; }
    }





    public override bool HasRows
    {
      get { return _sqlDr.HasRows; }
    }





    public override System.Collections.IEnumerator GetEnumerator()
    {
      return _sqlDr.GetEnumerator();
      //throw new NotImplementedException();
    }





    public override String GetName(int i)
    {
      return _sqlDr.GetName(i);
    }





    public override String GetDataTypeName(int i)
    {
      if (_gfieldNames.Contains(_sqlDr.GetName(i)))
        //todo: update to valid string !!
        return "Geometry";
      else
        return _sqlDr.GetDataTypeName(i);
    }





    public override Type GetFieldType(int i)
    {
      if (_gfieldNames.Contains(_sqlDr.GetName(i)))
        return typeof(GeometryBase);
      else
        return _sqlDr.GetFieldType(i);
     }

    
    

    
    public override Object GetValue(int i)
    {
      if (_gfieldNames.Contains(_sqlDr.GetName(i)))
        return _gdoF.CreateGeometry(_sqlDr.GetSqlBytes(i).Value);
      else
        return _sqlDr.GetValue(i);
    }





    public override int GetValues(object[] values)
    {
      int i = 0, j = 0;
      for (; i < values.Length && j < _sqlDr.FieldCount; i++, j++)
      {
        values[i] = GetValue(j);
      }

      return i;
    }




    public override int GetOrdinal(string name)
    {
      return _sqlDr.GetOrdinal(name);
    }




    public override object this[int i]
    {
      get { return GetValue(i); }
    }




    public override object this[String name]
    {
      // Look up the ordinal and return 
      // the value at that position.
      get { return this[GetOrdinal(name)]; }
    }




    public override bool GetBoolean(int i)
    {
      return _sqlDr.GetBoolean(i);
    }

    public override byte GetByte(int i)
    {
      return _sqlDr.GetByte(i);
    }




    public override long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
    {
      return _sqlDr.GetBytes(i, fieldOffset, buffer, bufferoffset, length);
    }




    public override char GetChar(int i)
    {
      throw new NotSupportedException();
    }




    public override long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)
    {
      return _sqlDr.GetChars(i, fieldoffset, buffer, bufferoffset, length);
    }



    public override Guid GetGuid(int i)
    {
      return _sqlDr.GetGuid(i);
    }



    public override Int16 GetInt16(int i)
    {
      return _sqlDr.GetInt16(i);
    }



    public override Int32 GetInt32(int i)
    {
      return _sqlDr.GetInt32(i);
    }



    public override Int64 GetInt64(int i)
    {
      return _sqlDr.GetInt64(i);
    }



    public override float GetFloat(int i)
    {
      return _sqlDr.GetFloat(i);
    }



    public override double GetDouble(int i)
    {

      return _sqlDr.GetDouble(i);
    }



    public override String GetString(int i)
    {
      return _sqlDr.GetString(i);
    }



    public override Decimal GetDecimal(int i)
    {

      return _sqlDr.GetDecimal(i);
    }



    public override DateTime GetDateTime(int i)
    {
      return _sqlDr.GetDateTime(i);
    }



    public override bool IsDBNull(int i)
    {
      return _sqlDr.IsDBNull(i);
    }



    //public void Dispose()
    //{
    //  this.Dispose(true);
    //  System.GC.SuppressFinalize(this);
    //}



    protected override void Dispose(bool disposing)
    {
      if (disposing)
      {
        try
        {
          this.Close();
        }
        catch (Exception e)
        {
          throw new SystemException("An exception of type " + e.GetType() +
                                    " was encountered while closing the " + this.GetType().ToString() + ".");
        }
      }
    }


  }
}
